/*
 *  Copyright 2003 by Spectrum Digital Incorporated.
 *  All rights reserved. Property of Spectrum Digital Incorporated.
 */
 
/*
 *  ======== evmdm642_uart.c ========
 *  UART module for the EVMDM642
 */
 
#include <csl.h>

#include "evmdm642.h"
#include "evmdm642_uart.h"


/*
 *  ======== EVMDM642_UART_rset ========
 *  Set a UART register
 */
void EVMDM642_UART_rset(EVMDM642_UART_Handle hUart, Int16 regnum, Int16 regval)
{
    Int16 regindex, lcr;
    
    /* Register index is determined by lower 3 bits and the target UART */
    regindex = regnum & 0x7;
    if (hUart == 1)
        regindex += 8;
    
    /* If regnum between 0x08 and 0x0F, set bit 7 of LCR to access register */
    if ((regnum & 0x18) == 0x8)
    {
        lcr = EVMDM642_UART_rget(hUart, EVMDM642_UART_LCR);
        EVMDM642_UART_rset(hUart, EVMDM642_UART_LCR, lcr | 0x80);
        EVMDM642_rset(regindex, regval);
        EVMDM642_UART_rset(hUart, EVMDM642_UART_LCR, lcr);
    }
    else
    {
        EVMDM642_rset(regindex, regval);
    }
}


/*
 *  ======== EVMDM642_UART_rget ========
 *  Get the value of a UART register
 */
Int16 EVMDM642_UART_rget(EVMDM642_UART_Handle hUart, Int16 regnum)
{
    Int16 regindex, returnval, lcr;
    
    /* Register index is determined by lower 3 bits and the target UART */
    regindex = regnum & 0x7;
    if (hUart == 1)
        regindex += 8;
    
    /* If regnum between 0x08 and 0x0F, set bit 7 of LCR to access register */
    if ((regnum & 0x18) == 0x8)
    {
        lcr = EVMDM642_UART_rget(hUart, EVMDM642_UART_LCR);
        EVMDM642_UART_rset(hUart, EVMDM642_UART_LCR, lcr | 0x80);
        returnval = EVMDM642_rget(regindex);
        EVMDM642_UART_rset(hUart, EVMDM642_UART_LCR, lcr);
    }
    else
    {
        returnval = EVMDM642_rget(regindex);
    }
    
    return returnval;
}


/*
 *  ======== EVMDM642_UART_open ========
 *  Initialize UART and return handle
 */
EVMDM642_UART_Handle EVMDM642_UART_open(Int16 devid, Int16 baudrate, EVMDM642_UART_Config *config)
{
    EVMDM642_UART_Handle hUart;
    
    /* Assign handle */
    hUart = devid;
    
    /* Set registers based on config structure */
    EVMDM642_UART_rset(hUart, EVMDM642_UART_IER, config -> regs[0]);
    EVMDM642_UART_rset(hUart, EVMDM642_UART_FCR, config -> regs[1]);
    EVMDM642_UART_rset(hUart, EVMDM642_UART_LCR, config -> regs[2]);
    EVMDM642_UART_rset(hUart, EVMDM642_UART_MCR, config -> regs[3]);

    /* Set up baud divisor clock */
    EVMDM642_UART_rset(hUart, EVMDM642_UART_DLL, baudrate & 0xff);
    EVMDM642_UART_rset(hUart, EVMDM642_UART_DLH, (baudrate >> 8) & 0xff);
    
    /* Clear any outstanding receive characters */
    EVMDM642_UART_rget(hUart, EVMDM642_UART_RBR);
    
    return hUart;
}

/*
 *  ======== EVMDM642_UART_getChar ========
 *  Get one character of data from the UART
 */
Int16 EVMDM642_UART_getChar(EVMDM642_UART_Handle hUart)
{
    Int16 status;
    
    while(1)
    {
        status = EVMDM642_UART_rget(hUart, EVMDM642_UART_LSR);
        if ((status & 1) != 0)  // DR
            break;
    }
    
    return EVMDM642_UART_rget(hUart, EVMDM642_UART_RBR);
}

/*
 *  ======== EVMDM642_UART_putChar ========
 *  Send one character of data to the UART
 */
void EVMDM642_UART_putChar(EVMDM642_UART_Handle hUart, Uint16 data)
{
    Int16 status;
    
    while(1)
    {
        status = EVMDM642_UART_rget(hUart, EVMDM642_UART_LSR);
        if ((status & 0x20) != 0)  // THRE
            break;
    }
    
    EVMDM642_UART_rset(hUart, EVMDM642_UART_THR, data);
}

